#include "imtPublic.h"
#include "imtXmlParser.h"

#include <istream>

namespace iMate{

	XmlDocumentPtr XmlSerializer::parse(const String& xmlFileName)
	{
		XmlDocumentPtr docPtr;
		std::ifstream ifile(xmlFileName.c_str(), std::ios_base::in);
		if (ifile.is_open())
		{
			FileStreamDataStream stream(xmlFileName, &ifile, false);
			docPtr = parse(&stream);
		}
		return docPtr;
	}
	XmlDocumentPtr XmlSerializer::parse(DataStream* stream)
	{
		XmlDocumentPtr xmlDocPtr;
		if (stream && stream->size())
		{
			SafeHeaper heap(stream->size() +1);
			stream->read(heap, heap.size());
			heap.set((char)0, heap.size());

			XmlDocument* doc = new XmlDocument();
			doc->Parse(heap);
			xmlDocPtr.bind(doc);
			mXmlFileName = stream->getName();
		}
		return xmlDocPtr;
	}
	bool XmlSerializer::write(XmlDocument* xmlDoc, const String& xmlFileName)
	{
		if (xmlDoc)
		{
			String filename = (xmlFileName == "") ? mXmlFileName : xmlFileName;
			xmlDoc->SaveFile(filename.c_str());
			mXmlFileName = filename;
			return true;
		}
		return false;
	}

	XmlDocumentPtr XmlSerializer::parseOrCreateXmlDocument(const String& xmlFileName)
	{
		XmlDocumentPtr ptr = parse(xmlFileName);
		if (ptr.isNull())
		{
			ptr.bind(new XmlDocument());
			ptr->InsertEndChild(TiXmlDeclaration("1.0", "gb3212", ""));
		}
		return ptr;
	}	


	bool imtXmlQueryContent(const XmlElement* node, String& dest)
	{
		if (node)
		{
			const XmlNode* child = node->FirstChild();
			while (child)
			{
				const XmlText* textNode = node->ToText();
				if (textNode)
				{
					const char* str = textNode->Value();
					if (str)
					{
						dest = str;
						return true;
					}
					return false;
				}

				child = child->NextSibling();
			}
		}
		return false;
	}

	bool imtXmlHasAttrib(const XmlElement* node,const String& attrib)
	{
		return node && node->Attribute(attrib.c_str());
	}
	bool imtXmlQueryAttrib(const XmlElement* node, const String& attrib, String& val)
	{
		const char* str = 0;
		if (node && (str = node->Attribute(attrib.c_str())))
		{
			val = str;
			return true;
		}
		return false;
	}
	bool imtXmlQueryAttrib(const XmlElement* node, const String& attrib, Vector2& vecVal)
	{
		String str;
		if (imtXmlQueryAttrib(node, attrib, str))
		{
			vecVal = Ogre::StringConverter::parseVector2(str);
			return true;
		}
		return false;
	}
	bool imtXmlQueryAttrib(const XmlElement* node, const String& attrib, Vector3& vecVal)
	{
		String str;
		if (imtXmlQueryAttrib(node, attrib, str))
		{
			vecVal = Ogre::StringConverter::parseVector3(str);
			return true;
		}
		return false;
	}
	bool imtXmlQueryAttrib(const XmlElement* node, const String& attrib, Vector4& vecVal)
	{
		String str;
		if (imtXmlQueryAttrib(node, attrib, str))
		{
			vecVal = Ogre::StringConverter::parseVector4(str);
			return true;
		}
		return false;
	}
	bool imtXmlQueryAttrib(const XmlElement* node, const String& attrib, Quaternion& quaVal)
	{
		String str;
		if (imtXmlQueryAttrib(node, attrib, str))
		{
			quaVal = Ogre::StringConverter::parseQuaternion(str);
			return true;
		}
		return false;
	}
	bool imtXmlQueryAttrib(const XmlElement* node, const String& attrib, ColourValue& clrVal)
	{
		String str;
		if (imtXmlQueryAttrib(node, attrib, str))
		{
			clrVal = Ogre::StringConverter::parseColourValue(str);
			return true;
		}
		return false;
	}
	
	TiXmlElement* imtXmlSetAttrib(XmlElement* node, const String& attrib, const char* value)
	{
		assert(node);
		node->SetAttribute(attrib.c_str(), value);
		return node;
	}

	TiXmlElement* imtXmlFindOrAddChildElement(XmlNode* parent, const String& nodeName)
	{
		assert(parent);
		TiXmlElement* node = parent->FirstChildElement(nodeName.c_str());
		if (!node)
		{
			node = parent->InsertEndChild(TiXmlElement(nodeName.c_str()))->ToElement();
		}
		return node;
	}
	TiXmlElement* imtXmlFindOrAddChildElementMatched(XmlNode* parent, const String& nodeName,
		const String& attribName, const String& attribValue)
	{
		assert(parent);

		TiXmlElement* child = parent->FirstChildElement(nodeName.c_str());
		String value;
		while (child)
		{
			if (imtXmlQueryAttrib(child, attribName, value)
				&& value == attribValue)
			{
				return child;
			}

			child = child->NextSiblingElement(nodeName.c_str());
		}
		child = parent->InsertEndChild(TiXmlElement(nodeName.c_str()))->ToElement();
		if (child)
		{
			child->SetAttribute(attribName.c_str(), attribValue.c_str());
		}
		return child;
	}

}//iMate